﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LifeGame2.Models;
class ClassicConway : LifeGameCore{
    // Rules:
    // 1. A live cell will die when the live cells close to it are fewer than 2 (< 2);
    // 2. A live cell will die when the live cells close to it are more than 3 (> 3);
    // 3. A live cell will NOT die when the live cells close to it are equal to 3 (== 3);
    // 4. A DEAD cell will Revive when the live cells close to it are equal to 3 (== 3);
    public bool[,] Pre;
    public bool[,] Curr;
    public int Width { get; }
    public int Height { get; }

    private bool _init;

    public ClassicConway() {
        Width = 300;
        Height = 200;
        Curr = new bool[Height, Width];
        Pre = new bool[Height, Width];
    }
    public ClassicConway(int width, int height) {
        Width = width;
        Height = height;
        Curr = new bool[Height,Width];
        Pre = new bool[Height, Width];
    }
    public override void Seeding(List<int[]> seeds) {
        foreach (int[] seed in seeds) {
            Pre[seed[0], seed[1]] = Curr[seed[0], seed[1]] = true;
        }

        _init = true;
    }
    // line/100 的几率，是一个活细胞
    public override void RandomSeeding(int line) {
        Random rd = new Random();
        int last = 101,now;
        for (int i = 0; i < Height; ++i) {
            for (int j = 0; j < Width; ++j) {
                now = rd.Next(0, 101);
                if (now == last) {
                    now = rd.Next(0, 101); }

                last = now;
                if (now >= line) {
                    Pre[i, j] = true;
                }
            }
        }

        _init = true;
    }

    // Rules:
    // 1. A live cell will die when the live cells close to it are fewer than 2 (< 2);
    // 2. A live cell will die when the live cells close to it are more than 3 (> 3);
    // 3. A live cell will NOT die when the live cells close to it are equal to 3 (== 3);
    // 4. A DEAD cell will Revive when the live cells close to it are equal to 3 (== 3);
    private static readonly sbyte[] Dx = { 1, 1, 1, 0, -1, -1, -1, 0 };
    private static readonly sbyte[] Dy = { -1, 0, 1, 1, 1, 0, -1, -1 };
    private const sbyte K8 = 8;

    public override bool[,] NextTurn() {
        if (! _init) return null;

        (Pre, Curr) = (Curr, Pre);
        for (int i = 0; i < Height; ++i) {
            for (int j = 0; j < Width; ++j) {
                sbyte live = 0;
                if (Pre[i, j]) {
                    for (sbyte k = 0; k < K8; ++k) {
                        int vx = i + Dx[k], vy = j + Dy[k];
                        if (vx<0 || vx>=Height || vy<0 || vy>=Width) { continue;}
                        if (Pre[vx, vy]) {
                            ++live;
                        }
                        if (live > 3) {
                            break;
                        }
                    }

                    if (live < 2 || live > 3) {
                        Curr[i, j] = false;
                    } else {
                        Curr[i, j] = true;
                    }
                }else {
                    for (sbyte k = 0;k < K8;++k) {
                        int vx = i + Dx[k], vy = j + Dy[k];
                        if (vx < 0 || vx >= Height || vy < 0 || vy >= Width) continue;
                        if (Pre[vx, vy]) {
                            ++live;
                        }
                        if (live == 3) {
                            Curr[i, j] = true;
                            break;
                        }
                    }
                }
            }
        }

        return Curr;
    }
}